/* s2 - mark memory as 'considered meaningless'
   Copyright (C) 2018-2019 Ariadne Devos

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#ifndef _sHT_TAINT_H
#define _sHT_TAINT_H

#include <stddef.h>

/** Memory tainting

  Tainting is marking memory as meaningless. This module allows four modes
  of operation: do nothing, clear memory, inform MemorySanitizer and inform
  Valgrind's Memcheck.

  As of now, only integers can be tainted, until the need arises and the idea
  is implemented.

  The policy is chosing by setting @var{sHT_taint_policy} to:
  - @var{sHT_taint_policy_clear}: set to zero
  - @var{sHT_taint_policy_nothing}: do nothing (default)
  - @var{sHT_taint_policy_msan}: inform MemorySanitizer
  - @var{sHT_taint_policy_memcheck}: inform Valgrind's memcheck

  Integer variables can be tainted with @var{sHT_taint}, which takes an integer
  pointer. */

#define sHT_taint_policy_clear 0
#define sHT_taint_policy_nothing 1
#define sHT_taint_policy_msan 2
#define sHT_taint_policy_memcheck 3

#ifndef sHT_taint_policy
# define sHT_taint_policy sHT_taint_policy_nothing
#endif

#define _sHT_taint_req(e) \
	_Generic(*(e), \
		char: (e), \
		unsigned char: (e), \
		signed char: (e), \
		unsigned short: (e), \
		signed short: (e), \
		unsigned int: (e), \
		signed int: (e), \
		unsigned long: (e), \
		signed long: (e), \
		unsigned long long: (e), \
		signed long long: (e))

#if sHT_taint_policy == sHT_taint_policy_clear
/* Reduce exploitation oppurtunities. */
# define sHT_taint(e) \
	do { *_sHT_taint_req(e) = 0; } while (0)

#elif sHT_taint_policy == sHT_taint_policy_nothing
/* For when s2 has been proved correct. */
# define sHT_taint(e) \
	do { (void) _sHT_taint_req(e); } while (0)

#elif sHT_taint_policy == sHT_taint_policy_msan
/* Supported by certain versions of gcc and clang. */
# include <sanitizer/msan_interface.h>
/* While fuzzing. */
# define sHT_taint(e) \
	__msan_poison(_sHT_taint_req(e), sizeof(*(e)))

#elif sHT_taint_policy == sHT_taint_policy_memcheck
# include "memcheck.h"
# define sHT_taint(e) \
	VALGRIND_MAKE_MEM_UNDEFINED(_sHT_taint_req(e), sizeof(*(e)))

#else
# error unsupported taint policy
#endif

#endif
